// Copyright(c) Sonosemi Medical Ltd. Embedded Software Team.
// Author: Zhang Yisong(zhangyisong@sonosemi.com)

#pragma once

// #if CONFIG_MODBUS

#include "result.hpp"
#include <span>
#include <zephyr/modbus/modbus.h>
namespace zpp {

namespace modbus {

enum class written_status : uint8_t {};
enum class reg : uint16_t {};
enum class coil : uint16_t {};

namespace internal {

constexpr auto to_integer(reg value) -> uint16_t {
  return static_cast<uint16_t>(value);
}

constexpr auto to_integer(coil value) -> uint16_t {
  return static_cast<uint16_t>(value);
}

} // namespace internal

class rtu_client {
public:
  using holding_reg_value_type = int;
  rtu_client(uint8_t id, const char *iface_name)
      : m_id{id}, m_iface(modbus_iface_get_by_name(iface_name)) {
    constexpr modbus_iface_param param = {
        .mode = MODBUS_MODE_RTU,
        .rx_timeout = 50000,
        .serial = {.baud = 9600,
                   .parity = UART_CFG_PARITY_NONE,
                   .stop_bits_client = UART_CFG_STOP_BITS_1}};
    modbus_init_client(m_iface, param);
  }
  rtu_client(uint8_t id, const char *iface_name, modbus_iface_param &param)
      : m_id(id), m_iface(modbus_iface_get_by_name(iface_name)) {
    modbus_init_client(m_iface, param);
  }
  auto write_holding_reg(reg addr, uint16_t value) -> error_code {
    return to_error_code(modbus_write_holding_reg(
        m_iface, m_id, internal::to_integer(addr), value));
  }
  auto write_coil(coil addr, bool state) -> error_code {
    return to_error_code(
        modbus_write_coil(m_iface, m_id, internal::to_integer(addr), state));
  }

  auto read_holding_regs(reg start_addr,
                         std::span<uint16_t> buff) -> error_code {
    return to_error_code(modbus_read_holding_regs(
        m_iface, m_id, internal::to_integer(start_addr), buff.data(),
        buff.size()));
  }

private:
  const uint8_t m_id;
  const int m_iface;
};

} // namespace modbus

} // namespace zpp

// #endif